package com.burst.reptile.modular.api.controller;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.thymeleaf.context.WebContext;
import org.thymeleaf.spring5.view.ThymeleafViewResolver;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.burst.reptile.common.constant.Constants;
import com.burst.reptile.common.constant.HttpStatus;
import com.burst.reptile.common.exception.CustomException;
import com.burst.reptile.common.exception.job.TaskException;
import com.burst.reptile.common.utils.Base64Util;
import com.burst.reptile.common.utils.SecurityUtils;
import com.burst.reptile.common.utils.ToolUtil;
import com.burst.reptile.common.utils.file.FileUploadUtils;
import com.burst.reptile.common.utils.textreview.TextContent;
import com.burst.reptile.framework.aspectj.lang.annotation.DelRes;
import com.burst.reptile.framework.aspectj.lang.annotation.Log;
import com.burst.reptile.framework.aspectj.lang.annotation.Msg;
import com.burst.reptile.framework.aspectj.lang.enums.BusinessType;
import com.burst.reptile.framework.aspectj.lang.enums.MsgType;
import com.burst.reptile.framework.config.CrawlerConfig;
import com.burst.reptile.framework.redis.RedisCache;
import com.burst.reptile.framework.tencent.CosPutObject;
import com.burst.reptile.framework.web.controller.BaseController;
import com.burst.reptile.framework.web.result.LayuiResult;
import com.burst.reptile.framework.web.result.Result;
import com.burst.reptile.modular.api.form.QueryResForm;
import com.burst.reptile.modular.api.form.ResourcesForm;
import com.burst.reptile.modular.api.form.UserInfoForm;
import com.burst.reptile.modular.api.form.UserPwdForm;
import com.burst.reptile.modular.api.vo.PublishRes;
import com.burst.reptile.modular.system.entity.SysUser;
import com.burst.reptile.modular.system.service.ISysUserService;
import com.burst.reptile.modular.zp.entity.ZpCollect;
import com.burst.reptile.modular.zp.entity.ZpFans;
import com.burst.reptile.modular.zp.entity.ZpFollow;
import com.burst.reptile.modular.zp.entity.ZpResources;
import com.burst.reptile.modular.zp.entity.ZpVote;
import com.burst.reptile.modular.zp.service.IZpCollectService;
import com.burst.reptile.modular.zp.service.IZpFansService;
import com.burst.reptile.modular.zp.service.IZpFollowService;
import com.burst.reptile.modular.zp.service.IZpResourcesService;
import com.burst.reptile.modular.zp.service.IZpVoteService;
import com.burst.reptile.modular.zp.warpper.UserWrapper;
import com.burst.reptile.modular.zp.warpper.ZpCollectWrapper;
import com.burst.reptile.modular.zp.warpper.ZpFansWrapper;
import com.burst.reptile.modular.zp.warpper.ZpFollowWrapper;
import com.burst.reptile.modular.zp.warpper.ZpResourcesWrapper;
import com.burst.reptile.modular.zp.warpper.ZpVoteWrapper;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;

/**
 * 找铺接口API
 * 
 * @author wujin
 *
 * @date: 2020年6月16日 下午9:44:00
 */
@RestController
@RequestMapping("/api/zp")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class ZpApiController extends BaseController {

	private final IZpResourcesService resourcesService;

	private final RedisCache redisCache;

	private final IZpVoteService voteService;

	private final IZpCollectService collectService;
	
	private final ThymeleafViewResolver thymeleafViewResolver;
	
	private final IZpFollowService followService;
	
	private final IZpFansService fansService;
	
	private final ISysUserService userService;
	
	private final CosPutObject cosPutObject;

	/**
	 * 点赞
	 * 
	 * @param id 文章ID
	 * @return
	 */
	@PostMapping("/vote/{id}")
	@Msg(businessType = MsgType.GIVE)
	public Result<Object> vote(@PathVariable String id) {
		if (!SecurityUtils.isLogin()) {
			throw new CustomException("未登录", HttpStatus.UNAUTHORIZED);
		}
		Long userId = SecurityUtils.getLoginUserId();
		String key = "vote_" + id + "_" + userId;
		String cacheObject = redisCache.getCacheObject(key);
		if (StrUtil.isNotEmpty(cacheObject)) {
			throw new CustomException("请勿频繁操作", HttpStatus.NOT_MODIFIED);
		}
		redisCache.setCacheObject(key, id);
		ZpResources resources = resourcesService.getById(id);
		if (ToolUtil.isEmpty(resources)) {
			redisCache.deleteObject(key);
			throw new CustomException("文章已被删除了", HttpStatus.MOVED_PERM);
		}
		// 添加点赞信息
		int res = voteService.add(userId, resources);
		redisCache.deleteObject(key);
		return Result.success(res);
	}

	/**
	 * 取消点赞
	 * 
	 * @param id 文章ID
	 * @return
	 */
	@PostMapping("/vote_cancel/{id}")
	public Result<Object> voteCancel(@PathVariable String id) {
		if (!SecurityUtils.isLogin()) {
			throw new CustomException("未登录", HttpStatus.UNAUTHORIZED);
		}
		Long userId = SecurityUtils.getLoginUserId();
		String key = "vote_cancel_" + id + "_" + userId;
		String cacheObject = redisCache.getCacheObject(key);
		if (StrUtil.isNotEmpty(cacheObject)) {
			throw new CustomException("请勿频繁操作", HttpStatus.NOT_MODIFIED);
		}
		redisCache.setCacheObject(key, id);
		// 移除点赞信息
		int res = voteService.del(userId, Long.valueOf(id));
		redisCache.deleteObject(key);
		return Result.success(res);
	}

	/**
	 * 收藏
	 * 
	 * @param id 文章ID
	 * @return
	 */
	@PostMapping("/collect/{id}")
	@Msg(businessType = MsgType.COLLECTION)
	public Result<Object> collect(@PathVariable String id) {
		if (!SecurityUtils.isLogin()) {
			throw new CustomException("未登录", HttpStatus.UNAUTHORIZED);
		}
		Long userId = SecurityUtils.getLoginUserId();
		String key = "collect_" + id + "_" + userId;
		String cacheObject = redisCache.getCacheObject(key);
		if (StrUtil.isNotEmpty(cacheObject)) {
			throw new CustomException("请勿频繁操作", HttpStatus.NOT_MODIFIED);
		}
		redisCache.setCacheObject(key, id);
		ZpResources resources = resourcesService.getById(id);
		if (ToolUtil.isEmpty(resources)) {
			redisCache.deleteObject(key);
			throw new CustomException("文章已被删除了", HttpStatus.MOVED_PERM);
		}
		// 添加收藏信息
		int res = collectService.add(userId, resources);
		redisCache.deleteObject(key);
		return Result.success(res);
	}

	/**
	 * 取消收藏
	 * 
	 * @param id 文章ID
	 * @return
	 */
	@PostMapping("/collect_cancel/{id}")
	public Result<Object> collect_cancel(@PathVariable String id) {
		if (!SecurityUtils.isLogin()) {
			throw new CustomException("未登录", HttpStatus.UNAUTHORIZED);
		}
		Long userId = SecurityUtils.getLoginUserId();
		String key = "collect_cancel_" + id + "_" + userId;
		String cacheObject = redisCache.getCacheObject(key);
		if (StrUtil.isNotEmpty(cacheObject)) {
			throw new CustomException("请勿频繁操作", HttpStatus.NOT_MODIFIED);
		}
		redisCache.setCacheObject(key, id);
		int res = collectService.del(userId, Long.valueOf(id));
		redisCache.deleteObject(key);
		return Result.success(res);
	}

	/**
	 * 发布文章接口
	 * 
	 * @param resources
	 * @return
	 */
	@PostMapping("/publish")
	@Log(title = "发布资源", businessType = BusinessType.INSERT)
	public Result<Object> publish(@Validated @RequestBody ResourcesForm resources,
			HttpServletRequest request, 
			HttpServletResponse response,
			Model model) {
		boolean title = TextContent.examineText(resources.getTitle());
		if(title) {
			return Result.error("发布内容含敏感词汇");
		}
		boolean examineText = TextContent.examineText(resources.getContentText());
		if(examineText) {
			return Result.error("发布内容含敏感词汇");
		}
		PublishRes publishRes = resourcesService.add(resources);
		if(StrUtil.equals(resources.getDraft(), "0")) {
			model.addAttribute("res", publishRes);
			WebContext ctx = new WebContext(request, response, request.getServletContext(), request.getLocale(), model.asMap());
			String html = thymeleafViewResolver.getTemplateEngine().process("page/release", ctx);
			return Result.success(html);
		}
		return Result.success(publishRes.getId());
	}
	
	/**
	 * 更新文章接口
	 * 
	 * @param resources
	 * @return
	 */
	@PostMapping("/update")
	@Log(title = "更新资源", businessType = BusinessType.UPDATE)
	public Result<Object> update(@Validated @RequestBody ResourcesForm resources,
			HttpServletRequest request, 
			HttpServletResponse response,
			Model model) {
		boolean title = TextContent.examineText(resources.getTitle());
		if(title) {
			return Result.error("发布内容含敏感词汇");
		}
		boolean examineText = TextContent.examineText(resources.getContentText());
		if(examineText) {
			return Result.error("发布内容含敏感词汇");
		}
		PublishRes publishRes = resourcesService.update(resources);
		String draft = publishRes.getDraft();
		if(StrUtil.equals(draft, "0")) {
			model.addAttribute("res", publishRes);
			WebContext ctx = new WebContext(request, response, request.getServletContext(), request.getLocale(), model.asMap());
			String html = thymeleafViewResolver.getTemplateEngine().process("page/release", ctx);
			return Result.success(html);
		}
		return Result.success(publishRes);
	}
	
	/**
	 * 定时发布文章接口
	 * 
	 * @param resources
	 * @return
	 * @throws TaskException 
	 * @throws SchedulerException 
	 */
	@PostMapping("/regularRelease")
	@Log(title = "定时发布资源", businessType = BusinessType.INSERT)
	public Result<Object> regularRelease(@Validated @RequestBody ResourcesForm resources,
			HttpServletRequest request, 
			HttpServletResponse response,
			Model model) throws SchedulerException, TaskException {
		String timingTime = resources.getTimingTime();
		try {
			DateUtil.parse(timingTime);
		} catch (Exception e) {
			return Result.error("定时日期格式错误");
		}
		resources.setDraft("3");
		boolean title = TextContent.examineText(resources.getTitle());
		if(title) {
			return Result.error("发布内容含敏感词汇");
		}
		boolean examineText = TextContent.examineText(resources.getContentText());
		if(examineText) {
			return Result.error("发布内容含敏感词汇");
		}
		PublishRes publishRes = resourcesService.regularRelease(resources);
		return Result.success(publishRes.getId());
	}
	
	
	/**
	 * 更新定时发布文章接口
	 * 
	 * @param resources
	 * @return
	 * @throws TaskException 
	 * @throws SchedulerException 
	 */
	@PostMapping("/regularReleaseEdit")
	@Log(title = "更新定时发布资源", businessType = BusinessType.UPDATE)
	public Result<Object> regularReleaseEdit(@Validated @RequestBody ResourcesForm resources,
			HttpServletRequest request, 
			HttpServletResponse response,
			Model model) throws SchedulerException, TaskException {
		String timingTime = resources.getTimingTime();
		try {
			DateUtil.parse(timingTime);
		} catch (Exception e) {
			return Result.error("定时日期格式错误");
		}
		resources.setDraft("3");
		boolean title = TextContent.examineText(resources.getTitle());
		if(title) {
			return Result.error("发布内容含敏感词汇");
		}
		boolean examineText = TextContent.examineText(resources.getContentText());
		if(examineText) {
			return Result.error("发布内容含敏感词汇");
		}
		PublishRes publishRes = resourcesService.regularReleaseEdit(resources);
		return Result.success(publishRes.getId());
	}
	
	/**
	 * 关注用户
	 * @param userId 用户ID
	 * @return
	 */
	@PostMapping("/follow/{userId}")
	@Msg(businessType = MsgType.FANS)
	public Result<Object> follow(@PathVariable Long userId){
		followService.follow(userId);
		return SUCCESS;
	}

	/**
	 * 取关
	 * @param userId 用户ID
	 * @return
	 */
	@PostMapping("/takeOff/{userId}")
	public Result<Object> takeOff(@PathVariable Long userId){
		followService.takeOff(userId);
		return SUCCESS;
	}
	
	/**
	 * 分页获取用户资源列表
	 * @param query
	 * @return
	 */
	@GetMapping("/res/list")
	public LayuiResult<Object> reslist(QueryResForm query){
		Page<ZpResources> page = startPage();
		Long userId = query.getUserId();
		if(ToolUtil.isEmpty(userId) && SecurityUtils.isLogin()) {
			userId = SecurityUtils.getLoginUserId();
		}
		query.setUserId(userId);
		Page<ZpResources> pagelist = resourcesService.myPageList(page, query);
		new ZpResourcesWrapper(pagelist).wrap();
		return LayuiResult.success(pagelist.getTotal(), pagelist.getRecords());
	}
	
	/**
	 * 删除资源
	 * @param id 资源ID
	 * @return
	 */
	@PostMapping("/del/{id}")
	@Log(title = "删除资源", businessType = BusinessType.DELETE)
	@DelRes
	public Result<Object> del(@PathVariable String id){
		return Result.success(resourcesService.del(id));
	}
	
	/**
	 * 发布资源
	 * @param id 资源ID
	 * @return
	 */
	@PostMapping("/publish/{id}")
	@Log(title = "发布资源", businessType = BusinessType.UPDATE)
	public Result<Object> publish(@PathVariable String id){
		return Result.success(resourcesService.publish(id));
	}
	
	/**
	 * 设为仅我可见
	 * @param id 资源ID
	 * @return
	 */
	@PostMapping("/withdraw/{id}")
	@Log(title = "设为仅我可见", businessType = BusinessType.UPDATE)
	public Result<Object> withdraw(@PathVariable String id){
		ZpResources byId = resourcesService.getById(id);
		if(ToolUtil.isEmpty(byId)) {
			return Result.error("资源不存在！");
		}
		Long userId = byId.getUserId();
		Long loginUserId = SecurityUtils.getLoginUserId();
		if(loginUserId.equals(userId)) {
			byId.setDraft("2");
			return Result.success(resourcesService.updateById(byId));
		}
		return Result.error("禁止操作");
	}
	
	/**
	 * 设为公开
	 * @param id 资源ID
	 * @return
	 */
	@PostMapping("/recovery/{id}")
	@Log(title = "设为公开", businessType = BusinessType.UPDATE)
	public Result<Object> recovery(@PathVariable String id){
		ZpResources byId = resourcesService.getById(id);
		if(ToolUtil.isEmpty(byId)) {
			return Result.error("资源不存在！");
		}
		Long userId = byId.getUserId();
		Long loginUserId = SecurityUtils.getLoginUserId();
		if(loginUserId.equals(userId)) {
			byId.setDraft("0");
			return Result.success(resourcesService.updateById(byId));
		}
		return Result.error("禁止操作");
	}
	
	/**
	 * 分页获取用户关注列表
	 * @param query
	 * @return
	 */
	@GetMapping("/follow/list")
	public LayuiResult<Object> followlist(@RequestParam(required = false) Long userId){
		Page<ZpFollow> page = startPage();
		// 分页获取我的点赞列表 
		ZpFollow follow = new ZpFollow();
		follow.setUserId(userId);
		Page<ZpFollow> pageList = followService.pageList(page, follow); 
		new ZpFollowWrapper(pageList).wrap();
		return LayuiResult.success(pageList.getTotal(), pageList.getRecords());
	}
	
	/**
	 * 分页获取用户粉丝列表
	 * @param query
	 * @return
	 */
	@GetMapping("/fans/list")
	public LayuiResult<Object> fanslist(@RequestParam(required = false) Long userId){
		Page<ZpFans> page = startPage();
		// 分页获取我的点赞列表 
		ZpFans fans = new ZpFans();
		fans.setUserId(userId);
		Page<ZpFans> pageList = fansService.pageList(page, fans); 
		new ZpFansWrapper(pageList).wrap();
		return LayuiResult.success(pageList.getTotal(), pageList.getRecords());
	}
	
	/**
	 * 分页获取用户点赞列表
	 * @param query
	 * @return
	 */
	@GetMapping("/vote/list")
	public LayuiResult<Object> vote(@RequestParam(required = false) Long userId){
		Page<ZpVote> page = startPage();
		// 分页获取我的点赞列表 
		ZpVote vote = new ZpVote();
		vote.setUserId(userId);
		Page<ZpVote> pageList = voteService.pageList(page, vote); 
		new ZpVoteWrapper(pageList).wrap();
		return LayuiResult.success(pageList.getTotal(), pageList.getRecords());
	}
	
	/**
	 * 分页获取用户收藏列表
	 * @param query
	 * @return
	 */
	@GetMapping("/collect/list")
	public LayuiResult<Object> collect(@RequestParam(required = false) Long userId){
		Page<ZpCollect> page = startPage();
		// 分页获取我的点赞列表 
		ZpCollect collect = new ZpCollect();
		collect.setUserId(userId);
		Page<ZpCollect> pageList = collectService.pageList(page, collect); 
		new ZpCollectWrapper(pageList).wrap();
		return LayuiResult.success(pageList.getTotal(), pageList.getRecords());
	}
	
	/**
	 * 分页获取行业圈友列表
	 * @param query
	 * @return
	 */
	@GetMapping("/cr/list")
	public LayuiResult<Object> crlist(@RequestParam(required = false) String id){
		Page<SysUser> page = startPage();
		QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
		if(StrUtil.isNotEmpty(id)) {
			queryWrapper.eq("format_id", id);
		}
		queryWrapper.eq("user_type", "11");
		queryWrapper.orderByDesc("create_time");
		Page<SysUser> pageList = userService.page(page, queryWrapper); 
		new UserWrapper(pageList).wrap();
		return LayuiResult.success(pageList.getTotal(), pageList.getRecords());
	}
	
	/**
	 * 更新用户基础信息
	 * @param userInfo
	 * @return
	 */
	@PostMapping("/update/user/info")
	public Result<Object> updateUserInfo(@Validated @RequestBody UserInfoForm userInfo){
		return Result.success(userService.updateUserInfo(userInfo));
	}
	
	/**
	 * 更新用户基础信息
	 * @param userInfo
	 * @return
	 */
	@Log(title = "重置密码", businessType = BusinessType.UPDATE)
	@PostMapping("/update/user/pwd")
	public Result<Object> updateUserInfo(@Validated @RequestBody UserPwdForm userPwd){
		return Result.success(userService.updateUserPwd(userPwd));
	}
	
	/**
	 * 头像上传
	 */
	@PostMapping("/avatar")
	public Result<Object> avatar(@RequestBody String base64) throws IOException {
		MultipartFile file = Base64Util.base64ToMultipart(base64);
		if (!file.isEmpty()) {
			String bucketName = CrawlerConfig.getBucketName();
			Long loginUserId = SecurityUtils.getLoginUserId();
			String extension = FileUploadUtils.getExtension(file);
			String fileName = IdUtil.simpleUUID() + "." + extension;
			String key = Constants.AVATAR_KEY + fileName;
			String redisKey = Constants.UPLOAD_PROGRESS + loginUserId + ":" + IdUtil.simpleUUID();
			cosPutObject.put(file, bucketName, key, redisKey);
			String avatar = Constants.HTTPS + bucketName + "." + CrawlerConfig.getDomainName() + "/" + Constants.AVATAR_KEY + fileName;
			String username = SecurityUtils.getUsername();
			userService.updateUserAvatar(username, avatar);
			return Result.success("ok");
		}
		return Result.error("上传失败");
	}
	
	/**
	 * 保存头像
	 */
	@PostMapping("/avatarurl")
	public Result<Object> avatarurl(@RequestBody String imgurl) throws IOException {
		String username = SecurityUtils.getUsername();
		userService.updateUserAvatar(username, imgurl);
		return Result.success("ok");
	}
	
}
